package com.ygqh.baby.handler;

import com.alibaba.fastjson.JSON;
import com.ygqh.baby.ao.Message;
import com.ygqh.baby.ao.PromotionType;
import com.ygqh.baby.ao.ReturnStatus;
import com.ygqh.baby.ao.ReturnType;
import com.ygqh.baby.model.*;
import com.ygqh.baby.po.YgOrderDetail;
import com.ygqh.baby.po.YgReturnOrder;
import com.ygqh.baby.po.YgReturnOrderDetail;
import com.ygqh.baby.service.YgOrderDetailService;
import com.ygqh.baby.service.YgOrderService;
import com.ygqh.baby.service.YgReturnOrderDetailService;
import com.ygqh.baby.service.YgReturnOrderService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 〈退款金额处理器〉
 *
 * @author guohao
 * @date 2018/12/14 10:01
 * @since 1.0.0
 */
@Component
public class CalculateReturnPriceHandler {

    @Autowired
    private YgReturnOrderService ygReturnOrderService;
    @Autowired
    private YgOrderDetailService ygOrderDetailService;
    @Autowired
    private YgReturnOrderDetailService ygReturnOrderDetailService;
    @Autowired
    private YgOrderService ygOrderService;


    /**
     * 获取退货金额
     *
     * @param returnInfo 请求参数
     *                   orderId
     *                   skuInfos
     * @return Message
     */
    public Message getReturnPrice(YgReturnInfoModel returnInfo) {


        //获取退货订单明细
        List<YgOrderDetail> orderDetailList = ygOrderDetailService.findByOrderId(returnInfo.getOrderId());
        //获取该订单已退
        List<YgReturnOrderDetail> orderReturnedList = getOrderReturnedList(returnInfo.getOrderId());

        Map<Long, List<YgReturnOrderDetail>> longListMap = orderReturnedList.stream().collect(Collectors.groupingBy(YgReturnOrderDetail::getOdId));

        List<OrderDetailReturnWrapper> orderDetailAndReturnInfos = new ArrayList<>();
        orderDetailList.forEach(orderDetail -> {
            OrderDetailReturnWrapper orderDetailAndReturnInfo = new OrderDetailReturnWrapper();
            orderDetailAndReturnInfo.setOrderDetail(orderDetail);
            List<YgReturnOrderDetail> rodList = longListMap.get(orderDetail.getId());
            setRefundedInfo(orderDetailAndReturnInfo, rodList);
            orderDetailAndReturnInfos.add(orderDetailAndReturnInfo);
        });
        //获取剩余可退金额 含成长金额
        BigDecimal lastReturnPrice = getLastReturnPrice(orderDetailAndReturnInfos);

        if (lastReturnPrice.compareTo(BigDecimal.ZERO) <= 0) {
            return Message.error("该订单已经全部退款", lastReturnPrice);
        }
        for (ReturnSkuInfo thisReturn : returnInfo.getSkuInfos()) {
            for (OrderDetailReturnWrapper wrapper : orderDetailAndReturnInfos) {
                if (thisReturn.getOrderDetailId().equals(wrapper.getOrderDetail().getId())) {
                    OrderDetailReturnData returnData = wrapper.getReturnData();
                    if (returnData == null) {
                        returnData = new OrderDetailReturnData();
                    }
                    returnData.setThisReturnQuantity(thisReturn.getQuantity());
                    Long lastCount = wrapper.getOrderDetail().getQuantity() - wrapper.getReturnData().getReturnedCount();
                    if (lastCount < thisReturn.getQuantity()) {
                        return Message.error("商品" + wrapper.getOrderDetail().getProductName() + "退货已超出购买数量", lastCount);
                    }
                    calculateEachReturnSkuThisReturnPrice(wrapper);
                }
            }

        }

        ReturnPriceModel returnPriceModel = getReturnPriceModel(orderDetailAndReturnInfos);
        List<OrderDetailReturnData> returnDataList = orderDetailAndReturnInfos.stream().filter(wrapper -> wrapper.getReturnData().getThisReturnQuantity() > 0)
                .map(OrderDetailReturnWrapper::getReturnData).collect(Collectors.toList());
        returnInfo.setReturnPriceModel(returnPriceModel);
        returnInfo.setReturnPrice(returnPriceModel.getReturnPrice());
        returnInfo.setReturnDataList(returnDataList);
        returnInfo.setExpressPrice(BigDecimal.ZERO);
        return Message.success(returnInfo);
    }

    private BigDecimal getLastReturnPrice(List<OrderDetailReturnWrapper> orderDetailAndReturnInfos) {
        return orderDetailAndReturnInfos.stream().map(odAndRefund -> {
            YgOrderDetail orderDetail = odAndRefund.getOrderDetail();
            OrderDetailReturnData returnData = odAndRefund.getReturnData();
            BigDecimal refundedPrice = BigDecimal.ZERO;
            BigDecimal refundedAccountPrice = BigDecimal.ZERO;
            if (returnData != null) {
                refundedPrice = returnData.getRefundedPrice();
                refundedAccountPrice = returnData.getRefundedAccountPrice();
            }
            return orderDetail.getRealPrice().add(orderDetail.getAccountPrice())
                    .subtract(refundedPrice).subtract(refundedAccountPrice);
        }).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public ReturnPriceModel getReturnPriceModel(List<OrderDetailReturnWrapper> orderDetailAndReturnInfos) {
        /**
         * 剩余可退金额
         */

        BigDecimal totalPrice = BigDecimal.ZERO;
        BigDecimal accountPrice = BigDecimal.ZERO;
        BigDecimal refundedPrice = BigDecimal.ZERO;
        BigDecimal refundedAccountPrice = BigDecimal.ZERO;

        BigDecimal thisReturnPrice = BigDecimal.ZERO;
        for (OrderDetailReturnWrapper wrapper : orderDetailAndReturnInfos) {
            OrderDetailReturnData returnData = wrapper.getReturnData();
            YgOrderDetail orderDetail = wrapper.getOrderDetail();
            totalPrice = totalPrice.add(orderDetail.getRealPrice());
            accountPrice = accountPrice.add(orderDetail.getAccountPrice());
            if (returnData != null) {
                refundedPrice = refundedPrice.add(returnData.getRefundedPrice());
                refundedAccountPrice = refundedAccountPrice.add(returnData.getRefundedAccountPrice());

                if (returnData.getThisReturnQuantity().compareTo(0L) > 0) {
                    thisReturnPrice = thisReturnPrice.add(returnData.getThisReturnPrice());
                }
            }
        }
        BigDecimal lastRefundPrice = totalPrice.subtract(refundedPrice);
        BigDecimal lastRefundAccountPrice = accountPrice.subtract(refundedAccountPrice);

        BigDecimal subtract = thisReturnPrice.subtract(lastRefundPrice);

        BigDecimal thisRefundPrice;
        BigDecimal thisRefundAccountPrice = BigDecimal.ZERO;

        if (subtract.compareTo(BigDecimal.ZERO) >= 0) {
            thisRefundPrice = lastRefundPrice;
            if (lastRefundAccountPrice.compareTo(subtract) < 0) {
                thisRefundAccountPrice = lastRefundAccountPrice;
            } else {
                thisRefundAccountPrice = subtract;
            }
        } else {
            thisRefundPrice = thisReturnPrice;
        }

        ReturnPriceModel priceModel = new ReturnPriceModel();
        priceModel.setReturnPrice(thisReturnPrice);
        priceModel.setReturnProductPrice(thisRefundPrice);
        priceModel.setReturnAccountPrice(thisRefundAccountPrice);

        return priceModel;
    }

    private void calculateEachReturnSkuThisReturnPrice(OrderDetailReturnWrapper odAndRefund) {
        YgOrderDetail orderDetail = odAndRefund.getOrderDetail();
        OrderDetailReturnData returnData = odAndRefund.getReturnData();
        Long lastQuantity = orderDetail.getQuantity() - returnData.getThisReturnQuantity() - returnData.getReturnedCount();
        if (lastQuantity <= 0) {
            BigDecimal thisReturnPrice = orderDetail.getRealPrice().add(orderDetail.getAccountPrice())
                    .subtract(returnData.getRefundedPrice()).subtract(returnData.getRefundedAccountPrice());
            returnData.setThisReturnPrice(thisReturnPrice);
            return;
        }

        String promotionRemark = orderDetail.getPromotionRemark();
        PromotionBo promotionBo = JSON.parseObject(promotionRemark, PromotionBo.class);

        //普通数量
        Long ordinaryQuantity = orderDetail.getQuantity();

        //本次普通商品退货数量
        Long thisReturnOrdinaryQuantity = returnData.getThisReturnQuantity();


        //本次退货促销商品最终售价金额
        BigDecimal promotionPrice = BigDecimal.ZERO;

        if (PromotionType.Pack.equals(promotionBo.getType())) {
            ordinaryQuantity = ordinaryQuantity - promotionBo.getPackAmount();
            //剩余未退普通数量
            Long lastOrdinaryQuantity = ordinaryQuantity - returnData.getReturnedCount();

            if (lastOrdinaryQuantity < returnData.getThisReturnQuantity()) {
                if (lastOrdinaryQuantity > 0) {
                    thisReturnOrdinaryQuantity = lastOrdinaryQuantity;
                } else {
                    thisReturnOrdinaryQuantity = 0L;
                }
            }
            // 促销退货数量  本次退货数量 - 普通数量
            Long thisReturnPromotionQuantity = returnData.getThisReturnQuantity() - thisReturnOrdinaryQuantity;
            if (thisReturnPromotionQuantity > 0) {
                BigDecimal promotionSalePrice = promotionBo.getPackPrice().divide(new BigDecimal(promotionBo.getBuyCount()), 2, BigDecimal.ROUND_DOWN);
                promotionPrice = promotionSalePrice.multiply(new BigDecimal(thisReturnPromotionQuantity));
            }
        }
        BigDecimal ordinaryPrice = orderDetail.getSalePrice().subtract(orderDetail.getVipDisPrice()).multiply(new BigDecimal(thisReturnOrdinaryQuantity));
        BigDecimal apportionPriceSumValue = getApportionPriceSumValue(orderDetail, promotionBo, promotionPrice, ordinaryPrice);
        BigDecimal thisReturnPrice = ordinaryPrice.add(promotionPrice).subtract(apportionPriceSumValue);
        returnData.setThisReturnPrice(thisReturnPrice);
        System.out.println(JSON.toJSONString(odAndRefund));
    }


    private BigDecimal getApportionPriceSumValue(YgOrderDetail orderDetail, PromotionBo promotionBo, BigDecimal promotionPrice, BigDecimal ordinaryPrice) {
        BigDecimal thisReturnSkuPrice = ordinaryPrice.add(promotionPrice);
        BigDecimal returnMjDisPrice = BigDecimal.ZERO;
        BigDecimal returnYhqDisPrice = BigDecimal.ZERO;
        BigDecimal returnExpressPrice = BigDecimal.ZERO;
        //分摊满减
        if (BigDecimal.ZERO.compareTo(orderDetail.getMjDisPrice()) < 0) {
            returnMjDisPrice = orderDetail.getMjDisPrice().divide(getOdPriceForApportion(orderDetail, 1), 2, BigDecimal.ROUND_DOWN)
                    .multiply(thisReturnSkuPrice);
        }
        if (BigDecimal.ZERO.compareTo(orderDetail.getYhqDisPrice()) < 0 && !promotionBo.getSpecial()) {
            BigDecimal apportionPrice = ordinaryPrice;
            if (promotionBo.getUseCoupon() != null && promotionBo.getUseCoupon()) {
                apportionPrice = apportionPrice.add(promotionPrice);
            }
            returnYhqDisPrice = orderDetail.getYhqDisPrice().divide(getOdPriceForApportion(orderDetail, 2), 2, BigDecimal.ROUND_DOWN)
                    .multiply(apportionPrice);
        }
        if (BigDecimal.ZERO.compareTo(orderDetail.getExpressPrice()) < 0) {
            returnExpressPrice = orderDetail.getExpressPrice().divide(getOdPriceForApportion(orderDetail, 1), 2, BigDecimal.ROUND_DOWN)
                    .multiply(thisReturnSkuPrice);
        }
        return returnMjDisPrice.add(returnYhqDisPrice).add(returnExpressPrice);
    }


    /**
     * 获取用于分摊 优惠金额的总金额
     *
     * @param orderDetail 订单明细
     * @param apportion   分摊哪一金额    1： 满减。2：优惠券 3：运费 4: 成长金
     * @return BigDecimal
     */
    private BigDecimal getOdPriceForApportion(YgOrderDetail orderDetail, int apportion) {
        PromotionBo promotionBo = JSON.parseObject(orderDetail.getPromotionRemark(), PromotionBo.class);
        BigDecimal price = orderDetail.getRealPrice();
        if (apportion == 1) {
            //满减
            price.add(orderDetail.getAccountPrice()).add(orderDetail.getMjDisPrice())
                    .add(orderDetail.getYhqDisPrice()).subtract(orderDetail.getExpressPrice());
        } else if (apportion == 2) {
            price.add(orderDetail.getAccountPrice()).add(orderDetail.getYhqDisPrice())
                    .subtract(orderDetail.getExpressPrice()).subtract(promotionBo.getSpecialPrice());
        } else if (apportion == 3) {
            price.add(orderDetail.getAccountPrice()).subtract(orderDetail.getExpressPrice());
        } else if (apportion == 4) {
            price.add(orderDetail.getAccountPrice());
        } else {
            throw new RuntimeException("Please check apportion value. [1： 满减。2：优惠券 3：运费 4: 成长金]");
        }
        return price;
    }


    /**
     * 设置退货信息
     *
     * @param orderDetailAndReturnInfo 订单明细and退货信息
     * @param rodList                  当前订单明细的历史退货
     */
    private void setRefundedInfo(OrderDetailReturnWrapper orderDetailAndReturnInfo, List<YgReturnOrderDetail> rodList) {
        BigDecimal refundedPrice = BigDecimal.ZERO;
        BigDecimal refundedAccountPrice = BigDecimal.ZERO;
        Long refundedCount = 0L;
        if (CollectionUtils.isNotEmpty(rodList)) {
            for (YgReturnOrderDetail returnOrderDetail : rodList) {
                refundedPrice = refundedPrice.add(returnOrderDetail.getPrice());
                refundedAccountPrice = refundedAccountPrice.add(returnOrderDetail.getAccountPrice());
                refundedCount = refundedCount + returnOrderDetail.getAmount();
            }
        }
        OrderDetailReturnData orderDetailReturnData = new OrderDetailReturnData();
        orderDetailReturnData.setOdId(orderDetailAndReturnInfo.getOrderDetail().getId());
        orderDetailReturnData.setRefundedPrice(refundedPrice);
        orderDetailReturnData.setRefundedAccountPrice(refundedAccountPrice);
        orderDetailReturnData.setReturnedCount(refundedCount);
        orderDetailAndReturnInfo.setReturnData(orderDetailReturnData);
    }

    private List<YgReturnOrderDetail> getOrderReturnedList(Long orderId) {
        List<YgReturnOrder> returnList = ygReturnOrderService.findByOrderIdList(Collections.singletonList(orderId), ReturnType.Return);
        List<YgReturnOrder> returnedList = returnList.stream().filter(ro -> ro.getReturnStatus().equals(ReturnStatus.Complete)).collect(Collectors.toList());

        List<String> returnCodeList = returnedList.stream().map(YgReturnOrder::getReturnCode).collect(Collectors.toList());
        return ygReturnOrderDetailService.findByReturnCodeList(returnCodeList);
    }

}
